package com.glink.manage.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.glink.common.contants.BaseConstants;
import com.glink.common.exception.GeneralSimpleException;
import com.glink.common.util.BaseCommonUtils;
import com.glink.manage.domain.AttendanceBean;
import com.glink.manage.dto.attendance.AttendanceAddDTO;
import com.glink.manage.dto.attendance.AttendancePageDTO;
import com.glink.manage.dto.attendance.AttendancePageDateDTO;
import com.glink.manage.mapper.AttendanceMapper;
import com.glink.manage.service.*;
import com.glink.manage.vo.attendance.AttendanceDateDetailVO;
import com.glink.manage.vo.attendance.AttendancePageDateVO;
import com.glink.manage.vo.attendance.AttendancePageVO;
import com.glink.manage.vo.attendance.AttendanceProjectStatisticsVO;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, AttendanceBean> implements AttendanceService {

    @Value("${statistics.attendance.days:7}")
    private int peopleStatisticsDays;
    
    @Autowired
    private AttendanceMapper attendanceMapper;

    @Autowired
    private OrgService orgService;
    
    @Autowired
    private ConstructionWorkService constructionWorkService;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private ConstructionWorkSiteService constructionWorkSiteService;

    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(BaseConstants.DATE_FORMAT_SHORT_DATE_3);

    /**
     * 分页查询
     * @param attendancePageDTO 查询条件
     * @return 信息
     */
    @Override
    public IPage<AttendancePageVO> findAttendancePage(AttendancePageDTO attendancePageDTO) throws GeneralSimpleException {
        List<String> dataPermissionDepartmentOrgId = orgService.getDataPermissionDepartmentOrgId();
        boolean status = orgService.checkDepartment();
        List<String> workIdList = Lists.newArrayList();
        
        if(status){
            workIdList = constructionWorkService.findIdByProjectDepartmentObjIdIn(dataPermissionDepartmentOrgId);
            if(CollectionUtils.isEmpty(workIdList)){
                return new Page<>(attendancePageDTO.getPage(), attendancePageDTO.getSize());
            }
        }else{
            boolean generalContractingUnit = userService.checkGeneralContractingUnit();
            if(generalContractingUnit){
                workIdList = constructionWorkService.findGeneralContractingUnitAccessWorkId();
                
                if(CollectionUtils.isNotEmpty(dataPermissionDepartmentOrgId)) {
                    // 参建单位
                    attendancePageDTO.setUnitObjId(dataPermissionDepartmentOrgId.get(0));
                }else if(CollectionUtils.isNotEmpty(workIdList)){
                    return new Page<>(attendancePageDTO.getPage(), attendancePageDTO.getSize());
                }
            }else{
                if(CollectionUtils.isNotEmpty(dataPermissionDepartmentOrgId)){
                    // 参建单位
                    attendancePageDTO.setUnitObjId(dataPermissionDepartmentOrgId.get(0));
                }else{
                    return new Page<>(attendancePageDTO.getPage(), attendancePageDTO.getSize());
                }    
            }
        }

        // 创建分页对象，并指定泛型类型为 Map<String, Object>
        Page<AttendancePageVO> page = new Page<>(attendancePageDTO.getPage(), attendancePageDTO.getSize());
        IPage<AttendancePageVO> resultPage = null;
        if(CollectionUtils.isNotEmpty(workIdList) && StringUtils.isNotBlank(attendancePageDTO.getUnitObjId())){
            // 调用自定义查询方法
            resultPage = baseMapper.selectAttendanceStatisticsGeneralContractingUnit(page,
                    attendancePageDTO.getSearchStr(), attendancePageDTO.getUnitObjId(), attendancePageDTO.getStatisticalMonth(), workIdList);
        }else{
            // 调用自定义查询方法
            resultPage = baseMapper.selectAttendanceStatistics(page,
                    attendancePageDTO.getSearchStr(), attendancePageDTO.getUnitObjId(), attendancePageDTO.getStatisticalMonth(), workIdList);    
        }

        if(CollectionUtils.isNotEmpty(resultPage.getRecords())){
            resultPage.getRecords().forEach(result -> {
                if(StringUtils.isNotBlank(result.getPersonOrgId())){
                    result.setUnitName(orgService.findOrgNameByOrgId(result.getPersonOrgId()));
                }
            });
        }
        
        return resultPage;
    }

    /**
     * 查询个人的打卡信息和打卡日期
     * @param attendancePageDateDTO 查询条件，假设上下班是两条信息。主键ID不一样，不能用主键id ，用 身份证，姓名，统计月份来筛选两条。
     * @return 信息
     */
    @Override
    public IPage<AttendancePageDateVO> findAttendancePageDate(AttendancePageDateDTO attendancePageDateDTO) throws GeneralSimpleException {
        // 解析传入的统计月份，并计算出该月的第一天和最后一天
//        String statisticalMonth = attendancePageDateDTO.getStatisticalMonth();
//        YearMonth yearMonth = YearMonth.parse(statisticalMonth + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//        String startDate = yearMonth.atDay(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 获取该月的第一天
//        String endDate = yearMonth.atEndOfMonth().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 获取该月的最后一天

        List<AttendanceDateDetailVO> detailVOList = this.baseMapper.selectCheckinDateByCardAndSearchStrAndCheckinDateBetweenOrderByCheckinDateDesc(attendancePageDateDTO.getCard(), attendancePageDateDTO.getPersonOrgId(), attendancePageDateDTO.getSearchStr(), attendancePageDateDTO.getUnitObjId(), attendancePageDateDTO.getStatisticalMonth());
        if(CollectionUtils.isEmpty(detailVOList)){
            return new Page<>(attendancePageDateDTO.getPage(), attendancePageDateDTO.getSize());
        }
        
        List<List<AttendanceDateDetailVO>> partition = ListUtils.partition(detailVOList, attendancePageDateDTO.getSize());
        Integer pageNum = attendancePageDateDTO.getPage();
        pageNum = pageNum == 0 ? 0 : pageNum - 1;
        if(CollectionUtils.isEmpty(partition.get(pageNum))){
            return new Page<>(attendancePageDateDTO.getPage(), attendancePageDateDTO.getSize());
        }

        List<AttendanceDateDetailVO> tempCheckinDateList = partition.get(pageNum);

        LambdaQueryWrapper<AttendanceBean> queryWrapper = new LambdaQueryWrapper<>();

        if (StringUtils.isNotBlank(attendancePageDateDTO.getSearchStr())) {
            queryWrapper.and(w -> w.like(AttendanceBean::getCard, attendancePageDateDTO.getSearchStr())
                    .or().like(AttendanceBean::getName, attendancePageDateDTO.getSearchStr()));
        }
        
        // 明细查询
        queryWrapper.eq(StringUtils.isNotBlank(attendancePageDateDTO.getCard()), AttendanceBean::getCard, attendancePageDateDTO.getCard());
        queryWrapper.eq(StringUtils.isNotBlank(attendancePageDateDTO.getPersonOrgId()), AttendanceBean::getUnitObjId, attendancePageDateDTO.getPersonOrgId());

        List<String> checkDateList = tempCheckinDateList.stream().map(AttendanceDateDetailVO::getStatisticalMonth).distinct().collect(Collectors.toList());
        queryWrapper.in(AttendanceBean::getCheckinDate, checkDateList); // 添加日期范围查询条件
        
        List<String> cardList = tempCheckinDateList.stream().map(AttendanceDateDetailVO::getCard).distinct().collect(Collectors.toList());
        queryWrapper.in(AttendanceBean::getCard, cardList);

        List<String> ordIdList = tempCheckinDateList.stream().map(AttendanceDateDetailVO::getPersonOrgId).distinct().collect(Collectors.toList());
        queryWrapper.in(AttendanceBean::getUnitObjId, ordIdList);

        // 排序
        queryWrapper.orderByAsc(AttendanceBean::getCheckinDate);
        queryWrapper.orderByAsc(AttendanceBean::getCard);
        queryWrapper.orderByAsc(AttendanceBean::getObjId);
        
        // 执行查询
        List<AttendanceBean> attendanceBeanList = attendanceMapper.selectList(queryWrapper);
        if(CollectionUtils.isEmpty(attendanceBeanList)){
            return new Page<>(attendancePageDateDTO.getPage(), attendancePageDateDTO.getSize());
        }

        Map<String, List<AttendanceBean>> attendanceBeanMap = Maps.newHashMap();
        attendanceBeanList.forEach(attendanceBean -> {
            String key = attendanceBean.getCard() + attendanceBean.getUnitObjId() + attendanceBean.getCheckinDate();
            if(attendanceBeanMap.containsKey(key)){
                attendanceBeanMap.get(key).add(attendanceBean);
            }else{
                List<AttendanceBean> beanList = Lists.newArrayList();
                beanList.add(attendanceBean);
                attendanceBeanMap.put(key, beanList);
            }
        });

        List<AttendancePageDateVO> vos = attendanceBeanMap.values().stream().map(valueList -> {
            AttendancePageDateVO attendancePageDateVO = new AttendancePageDateVO();
            if (CollectionUtils.isNotEmpty(valueList)) {
                AttendanceBean attendanceBean = valueList.get(0);
                attendancePageDateVO.setConstructionWorkObjId(attendanceBean.getConstructionWorkObjId());
                if (StringUtils.isNotBlank(attendanceBean.getConstructionWorkObjId())) {
                    attendancePageDateVO.setConstructionWorkName(constructionWorkService.findNameByObjId(attendanceBean.getConstructionWorkObjId()));
                }

                attendancePageDateVO.setConstructionWorkSiteObjId(attendanceBean.getConstructionWorkSiteObjId());
                if (StringUtils.isNotBlank(attendanceBean.getConstructionWorkSiteObjId())) {
                    attendancePageDateVO.setConstructionWorkSiteName(constructionWorkSiteService.findNameByObjId(attendanceBean.getConstructionWorkSiteObjId()));
                }

                LocalDate checkinDate = attendanceBean.getCheckinDate();
                // 使用预定义的格式化模式
                DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE;
                attendancePageDateVO.setCheckinDate(checkinDate.format(dateFormatter));


                List<LocalTime> localTimes = valueList.stream().map(AttendanceBean::getCheckinTime).collect(Collectors.toList());

                // 按12点分割上午和下午
                LocalTime noon = LocalTime.of(12, 0);
                List<LocalTime> morningTimes = localTimes.stream()
                        .filter(t -> t.isBefore(noon))
                        .collect(Collectors.toList());
                List<LocalTime> afternoonTimes = localTimes.stream()
                        .filter(t -> !t.isBefore(noon))
                        .collect(Collectors.toList());

                // 构建结果字符串
                StringBuilder result = new StringBuilder();
                DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");

                // 处理上午时间（取最早）
                if (!morningTimes.isEmpty()) {
                    LocalTime earliestMorning = morningTimes.stream()
                            .min(LocalTime::compareTo)
                            .orElseThrow(() -> new RuntimeException("无有效上午打卡时间"));
                    result.append("上午").append(earliestMorning.format(timeFormatter));
                }

                // 处理下午时间（取最晚）
                if (!afternoonTimes.isEmpty()) {
                    LocalTime latestAfternoon = afternoonTimes.stream()
                            .max(LocalTime::compareTo)
                            .orElseThrow(() -> new RuntimeException("无有效下午打卡时间"));
                    // 使用 length() 检查 StringBuilder 是否已有内容
                    if (result.length() > 0) {
                        result.append(" ");
                    }
                    result.append("下午").append(latestAfternoon.format(timeFormatter));
                }

                attendancePageDateVO.setCheckinTime(result.toString());
            }
            return attendancePageDateVO;
        }).sorted(Comparator.comparing(AttendancePageDateVO::getCheckinDate)).collect(Collectors.toList());

        // 设置分页结果
        Page<AttendancePageDateVO> resultPage = new Page<>(pageNum, attendancePageDateDTO.getSize(), vos.size());
        resultPage.setRecords(vos);
        return resultPage;
    }


    /**
     * 导出出勤管理主页面（项目部/参建单位）
     * @param attendancePageDTO 导出出勤管理主页面（项目部/参建单位）
     * @param haveUnit 是否参建单位条件
     * @return 输出
     */
    @Override
    public ByteArrayOutputStream exportFindAttendancePage(AttendancePageDTO attendancePageDTO, String haveUnit) throws GeneralSimpleException, IOException {
        attendancePageDTO.setSize(Integer.MAX_VALUE);
        // 获取考勤数据
        IPage<AttendancePageVO> findAttendancePageVO = findAttendancePage(attendancePageDTO);

        // 1. 创建 Excel 工作簿
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("出勤信息");

        // 定义表头，根据haveUnit来判断是那一种导出格式数据
        String[] headers;
        if ("Unit".equals(haveUnit)) {
            headers = new String[]{"身份证", "姓名", "所属参建单位", "统计月份", "出勤天数"};
        } else if ("noUnit".equals(haveUnit)) {
            headers = new String[]{"身份证", "姓名", "统计月份", "出勤天数"};
        } else {
            throw new GeneralSimpleException("无效的参数haveUnit：" + haveUnit);
        }

        // 2. 创建表头
        Row headerRow = sheet.createRow(0);
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
        }

        // 3. 填充数据
        int rowIndex = 1;
        for (AttendancePageVO attendancePageVO : findAttendancePageVO.getRecords()) {
            Row row = sheet.createRow(rowIndex++);
            row.createCell(0).setCellValue(attendancePageVO.getCard()); // 身份证
            row.createCell(1).setCellValue(attendancePageVO.getName()); // 姓名


            if ("Unit".equals(haveUnit)) {
                // 如果有"所属参建单位"这一列，则设置它的值
                row.createCell(2).setCellValue(attendancePageVO.getUnitName() != null ? attendancePageVO.getUnitName() : ""); // 所属参建单位
                row.createCell(3).setCellValue(attendancePageVO.getStatisticalMonth()); // 统计月份
                row.createCell(4).setCellValue(attendancePageVO.getAttendanceAllDay()); // 出勤天数
            } else {
                // 如果没有"所属参建单位"这一列，则直接从第2列开始填充剩余的数据
                row.createCell(2).setCellValue(attendancePageVO.getStatisticalMonth()); // 统计月份
                row.createCell(3).setCellValue(attendancePageVO.getAttendanceAllDay()); // 出勤天数

            }
        }


        // 4. 将工作簿内容写入字节流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();


        workbook.write(outputStream);
        workbook.close();

        // 5. 返回字节流
        return outputStream;
    }

    /**
     * 导出出勤管理主页面详情
     * @param attendancePageDateDTO 条件
     * @return 输出
     */
    @Override
    public ByteArrayOutputStream exportFindAttendancePageDate(AttendancePageDateDTO attendancePageDateDTO) throws GeneralSimpleException , IOException {
        attendancePageDateDTO.setSize(Integer.MAX_VALUE);
        //获取详细日期数据
        IPage<AttendancePageDateVO> findAttendancePageDateVO = findAttendancePageDate(attendancePageDateDTO);

        // 1. 创建 Excel 工作簿
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("出勤信息-详情");


        // 2. 创建表头
        Row headerRow = sheet.createRow(0);
        String[] headers = {"打卡日期","打卡时间"};
        for (int i = 0; i < headers.length; i++) {
            Cell cell = headerRow.createCell(i);
            cell.setCellValue(headers[i]);
        }


        // 3. 填充数据
        int rowIndex = 1;
        for (AttendancePageDateVO attendancePageDateVO : findAttendancePageDateVO.getRecords()) {
            Row row = sheet.createRow(rowIndex++);
            int cell = 0;
            row.createCell(cell ++).setCellValue(attendancePageDateVO.getConstructionWorkName());
            row.createCell(cell ++).setCellValue(attendancePageDateVO.getConstructionWorkSiteName());
            row.createCell(cell ++).setCellValue(attendancePageDateVO.getCheckinTime()); 
            row.createCell(cell).setCellValue(attendancePageDateVO.getCheckinTime()); 
        }

        // 4. 将工作簿内容写入字节流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        workbook.write(outputStream);
        workbook.close();

        // 5. 返回字节流
        return outputStream;
    }

    /**
     * 第三方设备信息接入保存数据库
     * @param attendanceAddDTO 添加信息条件
     * @return 状态
     */
    @Override
    public boolean addAttendance(AttendanceAddDTO attendanceAddDTO) throws GeneralSimpleException {
        // 格式校验（通过 @Pattern 注解自动触发）
        // 字符串 → 日期/时间类型
        LocalDate checkinDate = LocalDate.parse(attendanceAddDTO.getCheckinDate(), DateTimeFormatter.ISO_DATE);
        LocalTime checkinTime = LocalTime.parse(attendanceAddDTO.getCheckinTime(), DateTimeFormatter.ISO_TIME);

        // 生成一个新的设备ID(uuid)
        String deviceId= BaseCommonUtils.generateUUID();  // 调用生成的UUID的方法
        // 保存
        AttendanceBean attendanceBean = new AttendanceBean();
        attendanceBean.setObjId(deviceId);

        attendanceBean.setCard(attendanceAddDTO.getCard());
        attendanceBean.setName(attendanceAddDTO.getName());
        // 目前接收的是，公司id
        attendanceBean.setUnitObjId(attendanceAddDTO.getUnitObjId());

        attendanceBean.setCheckinDate(checkinDate);
        attendanceBean.setCheckinTime(checkinTime);

        return this.save(attendanceBean);

    }

    /**
     * 根据日期和工程统计
     *
     * @param workIdList 工程ID
     * @return 工程统计
     */
    @Override
    public List<AttendanceProjectStatisticsVO> projectStatisticsByDateAndWorkIdIn(List<String> workIdList) {
        // 结束天数
        LocalDate endDate = LocalDate.now();

        // 开始天数
        int days = peopleStatisticsDays > 0 ? peopleStatisticsDays - 1 : peopleStatisticsDays;
        LocalDate startDate = endDate.minusDays(days);
        List<AttendanceProjectStatisticsVO> statisticsVOList = this.baseMapper.statisticsAttendanceByCheckinDateBetweenAndWorkIdIn(startDate, endDate, workIdList);
        List<AttendanceProjectStatisticsVO> newStatisticsVOList = Lists.newArrayList();
        if(CollectionUtils.isNotEmpty(statisticsVOList)){
            Map<String, List<AttendanceProjectStatisticsVO>> statisticsMap = statisticsVOList.stream().collect(Collectors.groupingBy(AttendanceProjectStatisticsVO::getDateStr));
            while (startDate.isBefore(endDate) || startDate.isEqual(endDate)){
                String startDateStr = startDate.format(dateTimeFormatter);
                if(statisticsMap.containsKey(startDateStr)){
                    newStatisticsVOList.add(statisticsMap.get(startDateStr).get(0));
                }else{
                    AttendanceProjectStatisticsVO statisticsVO = new AttendanceProjectStatisticsVO();
                    statisticsVO.setDateStr(startDateStr);
                    statisticsVO.setReportPeopleCount(0);
                    newStatisticsVOList.add(statisticsVO);
                }

                startDate = startDate.plusDays(1);
            }
        }else{
            // 统计信息不存在，则初始化
            while (startDate.isBefore(endDate) || startDate.isEqual(endDate)){
                AttendanceProjectStatisticsVO statisticsVO = new AttendanceProjectStatisticsVO();
                statisticsVO.setDateStr(startDate.format(dateTimeFormatter));
                statisticsVO.setReportPeopleCount(0);
                newStatisticsVOList.add(statisticsVO);

                startDate = startDate.plusDays(1);
            }
        }
        return newStatisticsVOList;
    }

}
